% Simple graphics package with multiple inheritance

% Multiple inheritance design taken from Bertrand Meyer's
% book Object-Oriented Software Construction

% Author: Peter Van Roy

% Load QTk GUI tool from Mozart Standard Library
declare
[QTk]={Module.link ["x-oz://system/wp/QTk.ozf"]}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

declare

% Composite figure

% 1. LinkedList class

% Header node (marker, not part of list): @elem==null
% Last element: @next==null
% List empty: @elem==null and @next==null
class LinkedList
   attr elem next
   meth init(elem:E<=null next:N<=null)
      elem:=E next:=N
   end
   meth add(E)
      next:={New LinkedList init(elem:E next:@next)}
   end
   meth forall(P)
      if @elem\=null then {P @elem} end
      if @next\=null then {@next forall(P)} end
   end
   meth isempty($)
      @next==null
   end
end

% 2. Figure class

class Figure
   meth otherwise(M)
      raise inexistingMethodError end
   end
end

class Circle from Figure
   attr canvas x y r
   meth init(Canvas X Y R) 
      canvas:=Canvas
      x:=X y:=Y r:=R
   end
   meth move(X Y)
      x:=@x+X y:=@y+Y
   end
   meth display
      {@canvas create(oval @x-@r @y-@r @x+@r @y+@r)}
   end
end

class Line from Figure
   attr canvas x1 y1 x2 y2
   meth init(Canvas X1 Y1 X2 Y2)
      canvas:=Canvas
      x1:=X1 y1:=Y1 
      x2:=X2 y2:=Y2
   end
   meth move(X Y)
      x1:=@x1+X y1:=@y1+Y
      x2:=@x2+X y2:=@y2+Y
   end
   meth display
      {@canvas create(line @x1 @y1 @x2 @y2)}
   end
end

% 3. CompositeFigure class (with multiple inheritance)

% With this design, a figure can consist of other figures,
% some of which consist of other figures, and so forth,
% to any number of levels

class CompositeFigure from Figure LinkedList
   meth init
      LinkedList,init
   end
   meth move(X Y)
      {self forall(proc {$ F} {F move(X Y)} end)}
   end
   meth display
      {self forall(proc {$ F} {F display} end)}
   end
end

proc {DrawInit Canvas}
   Desc=td(title:"Simple graphics package"
	   canvas(width:250 height:150 bg:white handle:Canvas))
   Window={QTk.build Desc}
in
   {Window show} 
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Example

/*
declare
Canvas={DrawInit}
L1={New Line init(Canvas 50 50 150 50)}
L2={New Line init(Canvas 150 50 100 125)}
L3={New Line init(Canvas 100 125 50 50)}
C1={New Circle init(Canvas 100 75 20)}
F1={New CompositeFigure init}
{F1 add(L1)}
{F1 add(L2)}
{F1 add(L3)}
{F1 add(C1)}

{F1 display}
for I in 1..10 do {F1 display} {F1 move(3 ~2)} end
*/

